package com.summer.utils.md5;


import java.io.*;
import java.math.BigInteger;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.sql.SQLOutput;
import java.util.Arrays;
import java.util.Map;

/**
 * Md5：Message-Digest Algorithm
 * 生成小写的MD5字符 线程安全
 */
public class Md5Util {
	/**
	 * 默认的密码字符串组合，用来将字节转换成 16 进制表示的字符,apache校验下载的文件的正确性用的就是默认的这个组合
	 */
	protected static final char hexDigits[] = { '0', '1', '2', '3', '4', '5',
			'6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };

	/**
	 * 取小写MD5
	 */
	public static String getStringMD5(final String str) {
		MessageDigest messagedigest = null;
		try {
			messagedigest = MessageDigest.getInstance("MD5");
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		byte[] buffer = str.getBytes();
		messagedigest.update(buffer);
		return bufferToHex(messagedigest.digest());
	}

	public static String bufferToHex(byte bytes[]) {
		return bufferToHex(bytes, 0, bytes.length);
	}

	private static String bufferToHex(byte bytes[], int m, int n) {
		StringBuffer stringbuffer = new StringBuffer(2 * n);
		int k = m + n;
		for (int l = m; l < k; l++) {
			appendHexPair(bytes[l], stringbuffer);
		}
		return stringbuffer.toString();
	}

	private static void appendHexPair(byte bt, StringBuffer stringbuffer) {
		char c0 = hexDigits[(bt & 0xf0) >> 4];// 取字节中高 4 位的数字转换
		// 为逻辑右移，将符号位一起右移,此处未发现两种符号有何不同
		char c1 = hexDigits[bt & 0xf];// 取字节中低 4 位的数字转换
		stringbuffer.append(c0);
		stringbuffer.append(c1);
	}

	/**
	 * 获取文件的md5，把文件内容拼接成string
	 * @param file
	 * @return
	 */
	 public static String getFileMD5(final File file) {
			FileInputStream fis = null;
			MessageDigest messagedigest = null;
			try {
				fis = new FileInputStream(file);
				messagedigest = MessageDigest.getInstance("MD5");
				byte[] buffer = new byte[1024];
				int length;
				while ((length = fis.read(buffer)) != -1) {
					messagedigest.update(buffer, 0, length);
				}
				 byte b[] = messagedigest.digest(); 

		    	 int i; 
		    	 StringBuffer buf = new StringBuffer("");
		    	 for (int offset = 0; offset < b.length; offset++) { 
		    		 i = b[offset]; 
		    		 if(i<0) i+= 256; 
		    		 if(i<16) 
		    		 buf.append("0"); 
		    		 buf.append(Integer.toHexString(i));
		    		 } 
				return buf.toString();
			} catch (Exception e) {
				e.printStackTrace();
				throw new RuntimeException("error = "+e);
			} finally {
				try {
					fis.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	 /**
	 * return 16 bytes Md5 data
	 * @param bytes
	 * @return
	 */
	public static byte[] md5sum(byte[] bytes) {
		MessageDigest d;
		try {
			d = MessageDigest.getInstance("MD5");
		} catch (NoSuchAlgorithmException e) {
			throw new RuntimeException("MD5 algorithm not available!", e);
		}

		return d.digest(bytes);
	}



	/**
	 * 参数按字母正序排列
	 * @param params
	 * @return
	 */
	public static String paramsEncode(Map<String, Object> params) {

		StringBuffer paramsString = new StringBuffer();
		try {

			Object[] keys = params.keySet().toArray();
			Arrays.sort(keys);
			for (Object key : keys) {
				Object value = params.get(key);
				paramsString.append(key).append("=").append(value).append("&");
			}
			paramsString.delete(paramsString.length() - 1, paramsString.length());
			return paramsString.toString();
		} catch (Exception e) {
		}

		return "";
	}



	/**
	 * 字符串转MD5值
	 * @param psw
	 * @return
	 */
	public static String StringToMd5(String psw) {
		try {
			MessageDigest md5 = MessageDigest.getInstance("MD5");
			md5.update(psw.getBytes("UTF-8"));
			byte[] encryption = md5.digest();

			StringBuffer strBuf = new StringBuffer();
			for (int i = 0; i < encryption.length; i++) {
				if (Integer.toHexString(0xff & encryption[i]).length() == 1) {
					strBuf.append("0").append(Integer.toHexString(0xff & encryption[i]));
				} else {
					strBuf.append(Integer.toHexString(0xff & encryption[i]));
				}
			}

			return strBuf.toString().toLowerCase();
		} catch (NoSuchAlgorithmException e) {
			return "";
		} catch (UnsupportedEncodingException e) {
			return "";
		}
	}


	/**
	 * enCode编码
	 * @param param
	 * @return
	 */
	public static String urlEncodeStr(String param){
		String str = "";
		try {
			str = URLEncoder.encode(param, "UTF-8");
		} catch (UnsupportedEncodingException e) {
		}
		return str;
	}


	/**
	 * deCode解码
	 * @param param
	 * @return
	 */
	public static String urlDecodeStr(String param){
		String str = "";
		try {
			str = URLDecoder.decode(param, "UTF-8");
		} catch (UnsupportedEncodingException e) {
		}
		return str;
	}

	public static String getMd5ByFile(File file) {
		String value = null;
		FileInputStream in = null;
		try {
			in = new FileInputStream(file);
		} catch (FileNotFoundException e) {
		}
		try {
			MappedByteBuffer byteBuffer = in.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, file.length());
			MessageDigest md5 = MessageDigest.getInstance("MD5");
			md5.update(byteBuffer);
			BigInteger bi = new BigInteger(1, md5.digest());
			value = bi.toString(16);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if(null != in) {
				try {
					in.close();
				} catch (IOException e) {
				}
			}
		}
		return value;
	}

	public static String MD5Encode(String origin, String charsetName) {
		try {
			MessageDigest md = MessageDigest.getInstance("MD5");
			if (charsetName == null) {
				return bufferToHex(md.digest(origin.getBytes("utf-8")));
			} else {
				return bufferToHex(md.digest(origin.getBytes(charsetName)));
			}
		} catch (Exception e) {
			return null;
		}
	}


	public static void main(String[] args) {
		System.out.println(getStringMD5("my name is haoyitao"));

		String str = "445d 3489 bece 9459 db4d 13b5 ae59 e86a";

		BigInteger bigInteger = new BigInteger("1");
		for(int i=0;i<32;i++){
			bigInteger = bigInteger.multiply(new BigInteger("16"));
			System.out.println(bigInteger.toString());
		}


	}


}